package com.vmc.model;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.vmc.exception.VMCException;

public class DownloadTransferProperties {

	private List<String> allowedExtensions;
	private boolean isTvTransientUsed;
	private String sourceRootPath;
	private String tvDestinationRootPath;
	private String tvTransientPath;
	private String movieDestinationRootPath;
	private String movieTransientPath;
	private String movieConversionPath;
	protected File sourceDirectory;
	protected File tvDestinationDirectory;
	protected File tvTransientDirectory;
	protected File movieTransientDirectory;
	protected File movieDestinationDirectory;
	protected File movieConversionDirectory;
	
	public List<String> getAllowedExtensions() {
		return allowedExtensions;
	}

	public void setAllowedExtensions(List<String> allowedExtensions) {
		this.allowedExtensions = allowedExtensions;
	}

	public boolean isTvTransientUsed() {
		return isTvTransientUsed;
	}

	public void setTvTransientUsed(boolean isTvTransientUsed) {
		this.isTvTransientUsed = isTvTransientUsed;
	}

	public String getSourceRootPath() {
		return sourceRootPath;
	}

	public void setSourceRootPath(String sourceRootPath) {
		this.sourceRootPath = sourceRootPath;
	}

	public String getTvDestinationRootPath() {
		return tvDestinationRootPath;
	}

	public void setTvDestinationRootPath(String tvDestinationRootPath) {
		this.tvDestinationRootPath = tvDestinationRootPath;
	}

	public String getTvTransientPath() {
		return tvTransientPath;
	}

	public void setTvTransientPath(String tvTransientPath) {
		this.tvTransientPath = tvTransientPath;
	}

	public String getMovieDestinationRootPath() {
		return movieDestinationRootPath;
	}

	public void setMovieDestinationRootPath(String movieDestinationRootPath) {
		this.movieDestinationRootPath = movieDestinationRootPath;
	}

	public String getMovieTransientPath() {
		return movieTransientPath;
	}

	public void setMovieTransientPath(String movieTransientPath) {
		this.movieTransientPath = movieTransientPath;
	}

	public File getSourceDirectory() {
		return sourceDirectory;
	}

	protected void setSourceDirectory(File sourceDirectory) {
		this.sourceDirectory = sourceDirectory;
	}

	public File getTvDestinationDirectory() {
		return tvDestinationDirectory;
	}

	protected void setTvDestinationDirectory(File tvDestinationDirectory) {
		this.tvDestinationDirectory = tvDestinationDirectory;
	}

	public File getTvTransientDirectory() {
		return tvTransientDirectory;
	}

	protected void setTvTransientDirectory(File tvTransientDirectory) {
		this.tvTransientDirectory = tvTransientDirectory;
	}

	public File getMovieTransientDirectory() {
		return movieTransientDirectory;
	}

	protected void setMovieTransientDirectory(File movieTransientDirectory) {
		this.movieTransientDirectory = movieTransientDirectory;
	}

	public File getMovieDestinationDirectory() {
		return movieDestinationDirectory;
	}

	protected void setMovieDestinationDirectory(File movieDestinationDirectory) {
		this.movieDestinationDirectory = movieDestinationDirectory;
	}
	
	public String getMovieConversionPath() {
		return movieConversionPath;
	}

	public void setMovieConversionPath(String movieConversionPath) {
		this.movieConversionPath = movieConversionPath;
	}

	public File getMovieConversionDirectory() {
		return movieConversionDirectory;
	}

	public void setMovieConversionDirectory(File movieConversionDirectory) {
		this.movieConversionDirectory = movieConversionDirectory;
	}

	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
	}
	
	public static class Builder {
		
		static Logger logger = LogManager.getLogger(Builder.class);
		
		private static final String COMMA = ",";
		private static final String ALLOWED_EXTENSION_PROPERTY = "app.allowedExtensions";
		private static final String SOURCE_ROOT_PROPERTY = "source.root.path";
		private static final String MOVIE_DESTINATION_ROOT_PROPERTY = "movie.destination.root.path";
		private static final String TV_DESTINATION_ROOT_PROPERTY = "tv.destination.root.path";
		private static final String MOVIE_TRANSIENT_PATH_PROPERTY = "movie.transient.path";
		private static final String TV_TRANSIENT_PATH_PROPERTY = "tv.transient.path";
		private static final String TV_TRANSIENT_USED = "tv.useTransient";
		private static final String MOVIE_CONVERSION_PATH_PROPERTY = "movie.conversion.path";
		
		public static DownloadTransferProperties build(String propertiesPath, String alternatePath) throws VMCException {
			logger.info("Building the download transfer properties...");
			Properties properties = new Properties();
			try {
				File file = new File(propertiesPath);
				
				if (!file.exists() && alternatePath != null) {
					file = new File(alternatePath);
				}
				
				FileInputStream fileInputStream = new FileInputStream(file);
				properties.load(fileInputStream);
				fileInputStream.close();
			}
			catch (Exception e) {
				logger.error("An error occurred while building the download transfer properties.", e);
				throw new VMCException(e.getMessage());
			}
				
			logger.info("Done building the download transfer properties.");
			return build(properties);
		}
		
		public static DownloadTransferProperties build(String propertiesPath) throws VMCException {
			return build(propertiesPath, null);
		}
		
		public static DownloadTransferProperties build(Properties properties) throws VMCException {
			logger.info("Building the download transfer properties...");
			DownloadTransferProperties dtProperties = new DownloadTransferProperties();
			
			if (properties == null) {
				throw new VMCException(VMCException.INVALID_PROPERTIES_FILE);
			}
			
			if (properties.getProperty(ALLOWED_EXTENSION_PROPERTY) == null || properties.getProperty(ALLOWED_EXTENSION_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.ALLOWED_EXTENSION_PROPERTY_INVALID);
			}
			
			if (properties.getProperty(SOURCE_ROOT_PROPERTY) == null || properties.getProperty(SOURCE_ROOT_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.SOURCE_ROOT_PROPERTY_INVALID);
			}

			if (properties.getProperty(TV_DESTINATION_ROOT_PROPERTY) == null || properties.getProperty(TV_DESTINATION_ROOT_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.DESTINATION_ROOT_PROPERTY_INVALID);
			}
			
			if (properties.getProperty(TV_TRANSIENT_PATH_PROPERTY) == null || properties.getProperty(TV_TRANSIENT_PATH_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.TRANSIENT_ROOT_PROPERTY_INVALID);
			}

			if (properties.getProperty(MOVIE_DESTINATION_ROOT_PROPERTY) == null || properties.getProperty(MOVIE_DESTINATION_ROOT_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.DESTINATION_ROOT_PROPERTY_INVALID);
			}
			
			if (properties.getProperty(MOVIE_TRANSIENT_PATH_PROPERTY) == null || properties.getProperty(MOVIE_TRANSIENT_PATH_PROPERTY).isEmpty()) {
				throw new VMCException(VMCException.TRANSIENT_ROOT_PROPERTY_INVALID);
			}

			dtProperties.setAllowedExtensions(createAllowedExtensionsList(properties.getProperty(ALLOWED_EXTENSION_PROPERTY)));
			dtProperties.setSourceRootPath(properties.getProperty(SOURCE_ROOT_PROPERTY));
			dtProperties.setMovieDestinationRootPath(properties.getProperty(MOVIE_DESTINATION_ROOT_PROPERTY));
			dtProperties.setMovieTransientPath(properties.getProperty(MOVIE_TRANSIENT_PATH_PROPERTY));
			dtProperties.setTvDestinationRootPath(properties.getProperty(TV_DESTINATION_ROOT_PROPERTY));
			dtProperties.setTvTransientPath(properties.getProperty(TV_TRANSIENT_PATH_PROPERTY));
			dtProperties.setSourceDirectory(createFile(properties.getProperty(SOURCE_ROOT_PROPERTY), true, false));
			dtProperties.setMovieDestinationDirectory(createFile(properties.getProperty(MOVIE_DESTINATION_ROOT_PROPERTY), true, true));
			dtProperties.setMovieTransientDirectory(createFile(properties.getProperty(MOVIE_TRANSIENT_PATH_PROPERTY), true, true));
			dtProperties.setTvDestinationDirectory(createFile(properties.getProperty(TV_DESTINATION_ROOT_PROPERTY), true, true));
			dtProperties.setTvTransientDirectory(createFile(properties.getProperty(TV_TRANSIENT_PATH_PROPERTY), true, true));
			
			if (properties.getProperty(TV_TRANSIENT_USED) != null) {
				dtProperties.setTvTransientUsed(Boolean.parseBoolean(properties.getProperty(TV_TRANSIENT_USED)));
			}
			
			if (properties.getProperty(MOVIE_CONVERSION_PATH_PROPERTY) != null) {
				dtProperties.setMovieConversionPath(properties.getProperty(MOVIE_CONVERSION_PATH_PROPERTY));
				dtProperties.setMovieConversionDirectory(createFile(properties.getProperty(MOVIE_CONVERSION_PATH_PROPERTY), true, false));
			}
			
			logger.info("Done building the download transfer properties.");
			return dtProperties;
		}
		
		private static List<String> createAllowedExtensionsList(String allowedExtensions) {
			List<String> allowedExtensionsList = new ArrayList<String>();
			
			if (allowedExtensions != null) {
				StringTokenizer tokenizer = new StringTokenizer(allowedExtensions, COMMA);
				if (tokenizer != null) {
					while (tokenizer.hasMoreTokens()) {
						allowedExtensionsList.add(tokenizer.nextToken());
					}
				}
			}
			
			return allowedExtensionsList;
		}

		private static File createFile(String path, boolean checkCanRead, boolean checkCanWrite) throws VMCException {
			if (path == null) {
				throw new VMCException(VMCException.PATH_INVALID);
			}
			
			File directory = new File(path);
			
			if (!directory.exists()) {
				throw new VMCException(VMCException.NOT_EXISTING_PATH, path);
			}
			
			if (!directory.isDirectory()) {
				throw new VMCException(VMCException.NOT_A_DIRECTORY, path);
			}
			
			if (checkCanRead && !directory.canRead()) {
				throw new VMCException(VMCException.NOT_READABLE, path);
			}
			
			if (checkCanWrite && !directory.canWrite()) {
				throw new VMCException(VMCException.NOT_WRITABLE, path);
			}
			
			return directory;
		}
	}
}
